package com.huilam.restactions.filters;

import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.URLDecoder;
import java.util.Enumeration;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.huilam.restactions.common.HttpReqClient;
import com.huilam.restactions.common.RESTAction;
import com.huilam.restactions.common.util.ConfigUtil;
import com.huilam.restactions.common.util.HttpUtils;
import com.huilam.restactions.interfaces.IRESTAction;

public class RESTActionsFilter implements Filter  {
	
	public static final String RESTAction_version = "beta v0.8.0";
	
	private boolean debugMode = false;
	private ConfigUtil cfg = ConfigUtil.getInstance();
	
	private PrintStream printStream = System.out;


    public RESTActionsFilter() {
        super();
    }

	@Override
	public void doFilter(ServletRequest servletReq, ServletResponse servletRes,
			FilterChain chain) throws IOException, ServletException {

		HttpServletRequest req = (HttpServletRequest) servletReq;
		HttpServletResponse res = (HttpServletResponse) servletRes;
		
		boolean isDebug = "Y".equalsIgnoreCase(req.getParameter("debug"));
		
		HttpReqClient reqClient = new HttpReqClient(req, res);
		String[] paths = reqClient.getRequestPath();
		
		if(paths.length>0)
		{
			
			RESTAction ra = cfg.getRESTAction(reqClient);
	
			if(ra!=null)
			{
				StringBuffer sb = new StringBuffer();
				
				if(ra.isDebugMode() || debugMode || isDebug)
				{
					logClientInfo(req, res);
				}
	
				IRESTAction a = instantiateAction(ra);
				if(a!=null){
					
					String[] sModulePaths = HttpUtils.parseUri(ra.getModulePath());
					String[] sReqPaths = reqClient.getRequestPath();
					
					for(int i=0;i<sModulePaths.length; i++)
					{
						if(sModulePaths[i].startsWith("{")&&sModulePaths[i].endsWith("}"))
						{
							String sParamName = sModulePaths[i].substring(1, sModulePaths[i].length()-1);
							String sParamValue = URLDecoder.decode(sReqPaths[i],"UTF-8");
							reqClient.addRESTUrlParam(sParamName, sParamValue);
							if(ra.isDebugMode())
								log("[debug] Adding param - "+sParamName+"="+ sParamValue);
						}
					}
					sb.append(a.doActions(ra, reqClient));
				}
				
				//
		        if(sb.length()==0)
		        {
		        	sb.append("RESTaction error.");
		        }
		        
				///
				if(sb.length()>0)
				{
					PrintWriter out = res.getWriter();
					out.println(sb.toString());
					out.close();
					out.flush();
					if(ra!=null && ra.isDebugMode())
						log("[debug] "+sb.toString());
					
					return;
				}
			}
		}
		chain.doFilter(req,res);
	}
	
	protected boolean doAuthenticate(String aPaths[])
	{

		String sId 		= null;
		String sSecret 	= null;
	
		if(aPaths.length>=3)
			sId = aPaths[2];

		if(aPaths.length>=4)
			sSecret = aPaths[3];	
		
		return "restflow".equals(sId) && "secret".equals(sSecret);
	}
	
	private void logClientInfo(HttpServletRequest req, HttpServletResponse res)
	{
		
		log("===============================");
		log("remoteAddr="+req.getRemoteAddr());
		log("remotePort="+req.getRemotePort());
		log("remoteUser="+req.getRemoteUser());
		log("httpSession="+req.getSession(false));
		
		Enumeration<String> e = null;
		
		e = req.getHeaderNames();
		while(e.hasMoreElements())
		{
			String sKey = e.nextElement();
			String sValue = req.getHeader(sKey);
			log("header."+sKey+"="+sValue);
		}
		//
		Cookie[] cookies = req.getCookies();
		if(cookies!=null && cookies.length>0)
		{
			for(int i=0; i<cookies.length; i++)
			{
				Cookie c = cookies[i];
				log("cookie."+c.getDomain()+"."+c.getName()+"="+c.getValue());
			}
		}
		//
		e = req.getParameterNames();
		while(e.hasMoreElements())
		{
			String sKey = e.nextElement();
			String sValue = req.getHeader(sKey);
			log("reqParam."+sKey+"="+sValue);
		}
		//
		e = req.getAttributeNames();
		while(e.hasMoreElements())
		{
			String sKey = e.nextElement();
			String sValue = req.getHeader(sKey);
			log("reqAttr."+sKey+"="+sValue);
		}
		
	}
	
	public IRESTAction instantiateAction(RESTAction aRESTAction)
	{
		IRESTAction a = null;
		try {
			Class aClass = aRESTAction.getRESTActionClass();
			a = (IRESTAction) aClass.newInstance();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			a = null;
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			a = null;
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			a = null;
			e.printStackTrace();
		}		
		return a;
	}
	
	private void log(String aMsg)
	{
		printStream.println(aMsg);
	}

	public void setPrintStream(PrintStream aPrintStream)
	{
		printStream = aPrintStream;
	}
	
	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {
		// TODO Auto-generated method stub
		
	}
	
	public static void main(String args[])
	{
	}

}
